Import necessary modules¶
In [1]:
import pathlib
from ipyniivue import download_dataset
DATA_FOLDER = pathlib.Path("images")
download_dataset(
api_url="https://niivue.com/demos/images/",
dest_folder=DATA_FOLDER,
files=[
"example4d+orig.HEAD",
"example4d+orig.BRIK.gz",
],
)
Downloading example4d+orig.HEAD... Downloading example4d+orig.BRIK.gz... Dataset downloaded successfully to images.
In [2]:
import asyncio
import ipywidgets as widgets
from IPython.display import display
from ipyniivue import NiiVue, ShowRender, SliceType
# Create the NiiVue widget
nv = NiiVue()
nv.set_radiological_convention(False)
nv.set_slice_type(SliceType.MULTIPLANAR)
nv.opts.multiplanar_show_render = ShowRender.ALWAYS
# Configure graph values
nv.graph.auto_size_multiplanar = True
nv.graph.normalize_values = False
nv.graph.opacity = 1.0
# Load 4D volume with paired HEAD and BRIK files
nv.load_volumes(
[
{
"path": DATA_FOLDER / "example4d+orig.HEAD",
"paired_img_path": DATA_FOLDER / "example4d+orig.BRIK.gz",
"colormap": "gray",
"opacity": 1.0,
},
]
)
# Create other buttons/checkboxes
display_frame = widgets.Label(value="Volume: 0")
normalize_checkbox = widgets.Checkbox(
value=False,
description="Normalize Graph",
)
prev_button = widgets.Button(description="Back")
next_button = widgets.Button(description="Forward")
# Implement the callbacks
def on_normalize_change(change):
"""Normalize graph."""
nv.graph.normalize_values = change["new"]
normalize_checkbox.observe(on_normalize_change, names="value")
def on_prev_button_clicked(b):
"""Decrement the frame index."""
if nv.volumes:
current_frame = nv.volumes[0].frame_4d
new_frame = max(current_frame - 1, 0)
nv.volumes[0].frame_4d = new_frame
display_frame.value = f"Volume: {new_frame}"
def on_next_button_clicked(b):
"""Increment the frame index."""
if nv.volumes:
current_frame = nv.volumes[0].frame_4d
n_frames = nv.volumes[0].n_frame_4d
new_frame = min(current_frame + 1, n_frames - 1)
nv.volumes[0].frame_4d = new_frame
display_frame.value = f"Volume: {new_frame}"
prev_button.on_click(on_prev_button_clicked)
next_button.on_click(on_next_button_clicked)
# Create animate button
animate_button = widgets.Button(description="Animate")
animation_running = False
animation_task = None
async def animate_frames():
"""Animation loop."""
global animation_running
if not nv.volumes:
return
n_frames = nv.volumes[0].n_frame_4d
try:
while animation_running:
current_frame = nv.volumes[0].frame_4d
current_frame = (current_frame + 1) % n_frames
nv.volumes[0].frame_4d = current_frame
display_frame.value = f"Volume: {current_frame}"
await asyncio.sleep(0.1)
except asyncio.CancelledError:
pass
def on_animate_button_clicked(b):
"""Define 'Animate' button click handler."""
global animation_running, animation_task
if not animation_running:
# Start animation
animation_running = True
animate_button.description = "Stop"
# Schedule the animation coroutine and store the future
animation_task = asyncio.ensure_future(animate_frames())
else:
# Stop animation
animation_running = False
animate_button.description = "Animate"
# Cancel the running task if it's active
if animation_task is not None:
animation_task.cancel()
animation_task = None
animate_button.on_click(on_animate_button_clicked)
# Reset frame index on image loaded
@nv.on_image_loaded
def update_number_of_frames(volume):
"""Reset to first frame."""
nv.volumes[0].frame_4d = 0
display_frame.value = "Volume: 0"
# Display all
controls = widgets.HBox(
[
normalize_checkbox,
prev_button,
next_button,
animate_button,
]
)
display(widgets.VBox([controls, display_frame, nv]))